import { Player, SmartPlayer, UserPlayer } from "../playersystem/player";
import { CardsHeap } from "../cardsystem/cardHeap";
import { Card, CardType, Equipment } from "../cardsystem/card";
import GLOBAL_CONFIG from './gameconfig'
import { useStore } from 'vuex'
import {DeskCardInfoView, GameView, ViewStoreDispather} from '@/store/viewStore'
import { LogPrint } from "./logprint";
import UI from './uibrige';
import EQ from '@/core/cardsystem/equipments';
import BR from '@/core/cardsystem/brilliantness'
import { WaitForPushCardEvent } from '@/store/reactiveStore';



export class PlayerNode {
    player: Player
    next: PlayerNode
    constructor(player: Player, next: PlayerNode|null) {
        this.player = player
        this.next = next || this
    }

    // 求当前玩家距离为N的所有玩家
    distanceN(n: number, len: number): Player[] {
        let d = 0
        let curr = this.next
        const res: Player[] = []
        while(curr && curr != this) {
            d = d + 1
            const md = Math.min(d, len - d)
            const player = curr.player
            if (md + player.equipmentAreas.defendDistances <= n + this.player.equipmentAreas.actualDistance) {
                res.push(player)
            }
            curr = curr.next
        }
        
        return res;
    }
}

export class GameManager {
    allplayer: PlayerNode
    current: PlayerNode
    mainRole: PlayerNode
    maxPlayerCount: number
    currentPlayerCount: number
    cardHeap: CardsHeap
    logs: LogPrint
    private store: any
    

    constructor() {
        this.store = useStore()
        this.logs = new LogPrint()
        this.currentPlayerCount = this.maxPlayerCount = GLOBAL_CONFIG.GLOBAL_CONFIG.maxPlayerCount
        this.mainRole = this.allplayer = this.initPlayer(this.maxPlayerCount)
        this.current = this.initCurrent(this.maxPlayerCount)
        this.cardHeap = new CardsHeap()
        this.dispatchCard()
    }

    initPlayer(maxPlayer:number): PlayerNode {
        const firstPlayer: Player = new UserPlayer("玩家1", this)
        const head: PlayerNode = this.allplayer = new PlayerNode(firstPlayer, null)
        for (let i = 2; i <= maxPlayer; i++) {
            const name = "玩家" + i;
            const player: Player = new SmartPlayer(name, this)
            const next = new PlayerNode(player, null)
            this.allplayer.next = next
            this.allplayer = this.allplayer.next
        }
        this.allplayer.next = head
        return head
    }

    initCurrent(maxPlayer:number): PlayerNode {
        let current = this.allplayer
        const currentIndex = 0
        let newHead = new PlayerNode(this.allplayer.player, null)
        const head = newHead
        let currentNode = newHead
        for (let i = 1; i < maxPlayer; i++) {
            current = current.next
            newHead.next = new PlayerNode(current.player, null)
            if (i == currentIndex) {
                currentNode = newHead
            }
            newHead = newHead.next
        }
        newHead.next = head
        return currentNode
    }

    dispatchCard() {
        let curr = this.current
        for (let i = 0; i < this.maxPlayerCount; i++) {
            const player = curr.player
            const cards = this.cardHeap.drawCards(4)
            player.handCardAreas.setHandCard(cards)
            if (curr.next != null) {
                curr = curr.next
            }
        }
    }

    /**
     * 返回除当前以外的所有人
     */
    exceptCurrent(): Player[] {
        let curr = this.current.next
        const res: Player[] = []
        while(curr != null && curr != this.current) {
            res.push(curr.player)
            curr = curr?.next
        }
        return res;
    }

    allPlayerExceptMainRole(): Player[] {
        let curr = this.allplayer
        const mainRole = this.mainRole
        const res: Player[] = []
        do {
            if (!curr.player.equals(mainRole.player)) {
                res.push(curr.player)
            }
            curr = curr.next
        } while(curr != this.allplayer)
        return res;
    }

    /**
     * 返回在场所有人
     */
    presentPlayer(): Player[] {
        let curr = this.current
        const res: Player[] = []
        do {
            res.push(curr.player)
            curr = curr.next
        } while(curr != this.current)
        return res;
    }

    mainRolePlayer(): Player {
        return this.mainRole.player
    }

    currentPlayer(): Player {
        return this.current.player
    }

    returnCard(card: Card): void {
        this.cardHeap.returnCard(card)
    }

    /**
     * 发起一次判定 TODO 后续再加判定事件处理,这里先定义一个简单实现
     * @param player 谁
     * @param sourceCard 因为什么牌
     * @param predicate 收益条件,注意不是判定生效条件,是指期望得到什么牌才是对玩家有益的
     */
    launchJudge(player: Player, sourceCard: Card, predicate: (judge: Card) => boolean): Promise<Card | undefined> {
        const judgeCard = this.cardHeap.drawACard()
        if (judgeCard && judgeCard.cardProperties.owner == null && !judgeCard.cardProperties.reuse) {
            this.returnCard(judgeCard)
            judgeCard.onDrop()
        }
        return DefaultPromise(judgeCard)
    }

    // 求当前玩家距离为N的所有玩家
    distanceN(n: number): Player[] {
        return this.current.distanceN(n, this.currentPlayerCount)
    }
    // 求某个玩家距离为N
    playerDistanceN(player: Player, n: number): Player[] {
        if (this.current.player.equals(player)) {
            return this.distanceN(n)
        }
        let curr = this.current.next
        while(curr && curr != this.current) {
            if (curr.player.equals(player)) {
                return curr.distanceN(n, this.currentPlayerCount)
            }
            curr = curr.next
        }
        return []
    }

    removePlayer(player: Player) {
        // 回收死亡牌
        for(const c of player.handCardAreas.handCards) {
            c.onDrop()
        }
        for(const c of player.equipmentAreas.equipmentArea) {
            c && c.onDrop()
        }
        let curr = this.current
        let next = curr.next
        while ( next && curr.next && !next.player.equals(player)) {
            curr = curr.next
            next = next.next
        }
        if (curr && next) {
            curr.next = next.next
            this.currentPlayerCount = this.currentPlayerCount - 1
        }
        if (this.current.player.equals(player)) {
            this.current = this.current.next || this.current
        }

    }

    async waitForPickCard(canPickCards: Card[], canPickMin: number, canPickMax: number): Promise<WaitForPushCardEvent> {
        this.updateView()
        ViewStoreDispather.waitForPickCard(this.store, {canPickCards, canPickMin, canPickMax})
        return await UI.waitForClickButton()
    }

    async waitForPickPlayer(canPickPlayers: Player[], canPickMin: number, canPickMax: number): Promise<WaitForPushCardEvent> {
        this.updateView()
        ViewStoreDispather.waitForPickPlayer(this.store, {canPickPlayers, canPickMin, canPickMax})
        return await UI.waitForClickButton()
    }

    async waitForPickAllTypeCard(player: Player, canPickMin: number, canPickMax: number, pickRange?: CardType<Card>[]) {
        this.updateView()
        ViewStoreDispather.waitForPickAllTypeCard(this.store, player, canPickMin, canPickMax, pickRange)
        return await UI.waitForClickButton()
    }

    async waitForClickButton(): Promise<WaitForPushCardEvent> {
        return await UI.waitForClickButton()
    }

    clearDeskCard() {
        ViewStoreDispather.clearDeskCard(this.store)
    }
    appendDeskCard(card: Card) {
        ViewStoreDispather.appendDeskCard(this.store, card)
    }
    defineDeskCard(firstLine: string, nextLine: string, lastLine: string) {
        ViewStoreDispather.defineDeskCard(this.store, {firstLine, nextLine, lastLine})
    }

    async run() {
        this.appendLog("游戏初始化完成")
        while (this.currentPlayerCount > 1) {
            this.updateView()
            const currentPlayer = this.current.player
            await currentPlayer.turnrun()
            if (this.current.next != null) {
                this.current = this.current.next
            }
        }
        const currentPlayer = this.current.player
        this.appendLog(`恭喜 ${currentPlayer.name} 获胜`)
        return new Promise<void>(resolve => resolve())
    }

    updateView(needAsync=false) {
        const gv = new GameView(this)
        ViewStoreDispather.updateView(this.store, gv)
    }

    appendLog(msg: string) {
        ViewStoreDispather.appendLog(this.store, msg)
    }

    static create(): GameManager {
        
        const gameManager : GameManager = new GameManager()
        gameManager.updateView()
        // return gameManager
        return GameManagerTester.create()
    }

}

import { Jiu, Sha, Shan, Tao } from "@/core/cardsystem/basicCard";
import { DefaultPromise } from "../util/common";
import gameconfig from "./gameconfig";


/**
 * 本类仅用于开发过程中测试
 */
class GameManagerTester extends GameManager {

    dispatchCard() {
        this.beforeDispatch()

        super.dispatchCard()

        this.afterDispatch()
    }

    /**
     * 可以调整牌堆顺序控制自己想要摸的牌
     */
    beforeDispatch() {
        // 寒冰箭测试
        // this.equipCard(EQ.QingGangJian, this.current.player)
        // this.equipCard(EQ.Tengjia, this.current.next.player)
        // this.equipCard(EQ.HanBingJian, this.current.next.player)
        // this.equipCard(EQ.DiLu, this.current.next.next.next.player)
        // this.equipCard(EQ.ZiXing, this.current.next.player)

        // let swapIndex = 0
        // this.swapCardItem(BR.LeBuSiShu, swapIndex++)
        // this.swapCardItem(BR.GuoHeChaiQiao, swapIndex++)
        // this.swapCardItem(Jiu, swapIndex++)
        // this.swapCardItem(Jiu, swapIndex++)
        // this.swapCardItem(Sha, swapIndex++)
        // this.swapCardItem(Sha, swapIndex++)
        // this.swapCardItem(BR.WuXieKeJi, swapIndex++)
        // this.swapCardItem(BR.WuXieKeJi, swapIndex++)
        // this.swapCardItem(BR.WuXieKeJi, swapIndex++)
        // 寒冰箭测试 麒麟弓测试
        // this.swapCardItem(Tao, swapIndex++)
        // this.swapCardItem(Jiu, swapIndex++)
        // this.swapCardItem(Shan, swapIndex++)
        // this.swapCardItem(Shan, swapIndex++)
        // 贯石斧测试 青龙刀测试
        // this.swapCardItem(Sha, swapIndex++)
        // this.swapCardItem(Sha, swapIndex++)
        // this.swapCardItem(Sha, swapIndex++)
        // this.swapCardItem(Sha, swapIndex++)

        // swapIndex = this.maxPlayerCount * 4
        // for(let i = 1; i < this.maxPlayerCount; i++ ) {
        //     swapIndex = i * 4
        //     this.swapCardItem(BR.WuXieKeJi, swapIndex)
        // }
        
        // this.swapCardItem(Sha, swapIndex++)
        // 八卦阵测试
        // this.swapCardItem(Tengjia, swapIndex++) // 判定失败
        // this.swapCardItem(Tao, swapIndex++) // 判定成功
    }

    afterDispatch() {
        // 古锭刀测试
        // if (this.current.next) {
        //     const next = this.current.next
        //     const handCards = [...next.player.handCards].slice(0, next.player.handCards.length-1)
        //     for (const card of handCards) {
        //         next.player.dropCard(card)
        //         card.onDrop()
        //     }
        // }
        // const handCards = this.current.player.handCards
        // 方天画戟测试
        // this.current.player.handCards.pop()
        // this.current.player.handCards.pop()
        // this.current.player.handCards.pop()
        // 寒冰箭测试
        // this.current.next.player.reduceHP(3)
        // 锦囊牌测试
        // const next = this.current.next
        // const nextHandCards = [...next.player.handCards]
        // for (const card of nextHandCards) {
        //     if (!(card instanceof BR.WuXieKeJi)) {
        //         next.player.dropCard(card)
        //         card.onDrop()
        //     }
        // }
        // for(const player of this.allPlayer()) {
        //     player.reduceHP(1)
        // }

    }

    returnCard(card: Card): void {
        super.returnCard(card)
        const hasOwnerCards = this.cardHeap.allCards.filter(t => t.cardProperties.owner != null && t.id != card.id).map(t => t.id)
        const inuseCards = this.cardHeap.inuseCards.map(t => t.id)
        const useCards = this.cardHeap.usedCards.map(t => t.id)
        const combineCards = inuseCards.concat(useCards).concat(hasOwnerCards).sort((a, b) => a-b)
        if (this.cardHeap.allCards.length < combineCards.length) {
            let diff = combineCards.length - this.cardHeap.allCards.length
            let lastDup = combineCards[0]
            for(let i = 1; i < combineCards.length; i++) {
                const it = combineCards[i]
                if (lastDup == it) {
                    diff--
                    console.log(it, this.cardHeap)                    
                } else {
                    lastDup = it
                }
                if (diff <= 0) {
                    break
                }
            }
        } else if (this.cardHeap.allCards.length > combineCards.length) {
            let diff = this.cardHeap.allCards.length - combineCards.length
            let j = 0
            for(let i = 0; i < combineCards.length; i++) {
                if (this.cardHeap.allCards[i].id == combineCards[j]) {
                    j++
                } else {
                    diff--
                    console.log(j, combineCards[j], this.cardHeap.allCards[i].id, this.cardHeap)
                    if (diff <= 0) {
                        break
                    }
                }
            }
        }

    }

    swapCardItem<T extends Card>(target: CardType<T>, swapIndex: number) {
        const inuseCards = this.cardHeap.inuseCards
        for(let index =swapIndex; index < inuseCards.length; index ++) {
            const card = inuseCards[index]
            if (card instanceof target) {
                inuseCards[index] = inuseCards[swapIndex]
                inuseCards[swapIndex] = card
                break
            }
        }
    }

    /**
     * 给某位玩家配装备
     * @param target 装备
     * @param player 玩家
     */
    equipCard<T extends Equipment>(target: CardType<T>, player: Player) {
        this.swapCardItem(target, 0)
        const targetCard = this.cardHeap.drawACard()
        if (targetCard instanceof Equipment) {
            player.handCardAreas.acquireHandCard(targetCard)
            player.handCardAreas.useCard(targetCard)
            targetCard.use()
        }

    }

    static create(): GameManager {
        
        const gameManager : GameManager = new GameManagerTester()
        gameManager.updateView()

        return gameManager
    }

}